/**************************************************************************************
*
*	Copyright (C) 2009 - 2012 Brent Andrew O. Chua - See LICENSE.txt for more info.
*		
*	Filename	-	Scene
*
*	Description -	Scene (graph). Take note this is not a usual scene graph that 
*					everyone now hates. This is just a simple Transform graph.
*
*	Comments	-	The scene can switch nodes and change coordinate system.
*
*	Modification History:
*			Name			   Date					Description
*			MrCodeSushi	-	07/03/2012	-	Creation of this file
**************************************************************************************/
#ifndef _PSX_SCENE_H_
#define _PSX_SCENE_H_

#include "PulseSTD.h"
#include "Actor.h"
#include "EventSystem.h"
#include "List.h"

namespace Pulse
{
	class Scene
	{
	public:

		Scene( void );

		~Scene( void );

		Actor * GetRoot( void ) { return m_pRoot; }

		ActorPtr GetRootPtr( void ) { return m_pRoot; }

		Actor * GetTargetNode( void ) { return m_pRoot; }

		void FixedUpdate( const FLOAT dt );

		void Update( const FLOAT dt );

		// Uses the active camera's render view
		void Render( void );

		// Used for additional render views
		// NOTE: Parameters are not final yet.
		void Render( ComponentCamera *pCamera, RenderView *pView );

		void SetCamera( ActorPtr pCamera );

		ActorPtr GetCamera( void ) { return m_pActiveCamera; }

		ActorPtr NewActor( void );

		// TODO: NewActor with init node

		EErrorCode::Type Save( const CHAR *pFilename );

		IPhysicsSystem * GetPhysicsSystem( void ) { return m_pPhysics; }

	public:

		// Event management

		EventSystem * GetEventSystem( void ) { return &m_eventSystem; }

		// this, class member function
		// NOTE: WARNING! Make sure the func method accepts an EventPtr parameter. NOT IEvent*!
		template < typename ThisObject, typename Function >
		BOOL AddListener( const EEvent::Type event, ThisObject thisObject, Function func );

		// this, class member function
		// NOTE: WARNING! Make sure the func method accepts an EventPtr parameter. NOT IEvent*!
		template < typename ThisObject, typename Function >
		BOOL RemoveListener( const EEvent::Type event, ThisObject &thisObject, Function func );

		void TriggerEvent( IEvent *pEvent );

		void PostEvent( EventPtr pEvent );

	public:

		// Unsorted Utility Functions

		WindowView * GetWindowViewOwner( void ) { return m_pViewOwner; }
		
		const WindowView * GetWindowViewOwner( void ) const { return m_pViewOwner; }

		void ProcessDeferredComponentDestroy( void );

		void ProcessDeferreActorDestroy( void );

	private:

		void InsertActor( ActorPtr pActor );

		friend Actor;

		// Called by Actor::Destroy
		void QueueActorDestroy( ActorPtr pActor );

		void QueueComponentDestroy( IComponent *pComponent );

	private:

		friend WindowView;

		EErrorCode::Type Initialize( WindowView *pOwner );

		void Cleanup( void );

	private:

		FactoryActor *m_pFactoryActor;
		
		// Timer bookeeping for the fixed update functionality.
		//FLOAT m_fixedTimeStep; // Currently hardcoded
		FLOAT m_fixedTimeAccumulated;

		WindowView	*m_pViewOwner;
		ActorPtr	m_pRoot;	
		ActorPtr	m_pActiveCamera;

		typedef List<ActorPtr> ActorList;
		typedef List<IComponent*> ComponentList;

		// Add acceleration structures here...
		EventSystem		m_eventSystem;	// Scene specific events
		IPhysicsSystem *m_pPhysics;
		ActorList		m_deferredDestroyActors;
		ComponentList	m_deferredDestroyComponents;

	};

	// this, class member function
	template < typename ThisObject, typename Function >
	PSX_INLINE BOOL Scene::AddListener( const EEvent::Type event, ThisObject thisObject, Function func )
	{
		return m_eventSystem.AddListener< ThisObject, Function>( event, thisObject, func );
	}

	// this, class member function
	template < typename ThisObject, typename Function >
	PSX_INLINE BOOL Scene::RemoveListener( const EEvent::Type event, ThisObject &thisObject, Function func )
	{
		return m_eventSystem.RemoveListener( event, thisObject, func );
	}
}

#endif /* _PSX_SCENE_H_ */